package com.fjnu.aspect;


import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import com.fjnu.annotation.Cacheable;
import org.springframework.stereotype.Component;

import java.util.concurrent.ConcurrentHashMap;

@Component
@Aspect
@Slf4j
public class CacheableAspect {

    private final ConcurrentHashMap<String, Object> cacheManager = new ConcurrentHashMap<>() ;

    /**
     * 对所有打上注解 @Cacheable的方法进行缓存
     */

    @Pointcut("@annotation(cacheable)")
    public void cacheable(Cacheable cacheable) {}

    @Pointcut("@within(com.fjnu.annotation.Cacheable) && execution(* select*(..))")
    public void roleQueryCache(){}


    @Around("cacheable(cacheable)")
    public Object cacheableAroundAdvice(ProceedingJoinPoint jp, Cacheable cacheable)
            throws Throwable {

        log.info("Around advice start...");
        boolean needed = cacheable.needed() ;
        if (!needed) {
            return jp.proceed();
        }
        /**
         * cache logic
         */
        String key = cacheable.cacheName() + "_" + jp.getSignature().getName() ;
        long llt = cacheable.llt() ;
        Object ret = cacheManager.get(key) ;
        if (ret != null) {
            log.info("Got result from cache for key: {}", key);
            return ret ;
        }
        /**
         * cache miss: the first time query
         */
        ret = jp.proceed();
        // cache the result
        cacheManager.put(key, ret);
        log.info("Cache the result for key {}", key);
        return ret ;

    }

    @Around("roleQueryCache()")
    public Object roleQueryCacheAdvice(ProceedingJoinPoint jp) throws Throwable {
        log.info("RoleQueryCacheAround advice start method: {}...", jp.getSignature().getName());
        Object ret = jp.proceed() ;
        log.info("RoleQueryCacheAround advice end method:{}", jp.getSignature().getName());
        return ret;
    }


}
